#include <boost/json/src.hpp>
#include <jwt-cpp/jwt.h>

#include "LogicSystem.h"
#include "HttpConnection.h"
#include "RedisMng.h"
#include "Utils.hpp"
#include "MySQLDao.h"

using namespace utils;

LogicSystem::LogicSystem() {
    RegisterGet("/ping", [](const std::shared_ptr<HttpConnection>& connection) {
        connection->_response.set(http::field::content_type, "text/plain");
        beast::ostream(connection->_response.body()) << "pong";
    });

    RegisterPost("/login", [](const std::shared_ptr<HttpConnection>& connection) {
        auto params = str::splitHttpParams(buffers_to_string(connection->_request.body().data()));

        bool isSuccess = MySQLDao::GetInstance()->UserLogin(params["username"], params["password"]);
        if (isSuccess) {
            const string token = jwt::create()
                                 .set_type("JWS") //设置 JWT 的类型为 JWS（JSON Web Signature）
                                 .set_issuer("DataMonitor") //设置 JWT 的签发者为 DataMonitor
                                 .set_payload_claim("user", jwt::claim(params["username"])) //添加jwt载荷
                                 .set_expires_at(std::chrono::system_clock::now() + std::chrono::days(10)) //设置过期时间
                                 .sign(jwt::algorithm::hs256{"haitong"}); //使用 HS256 算法和密钥 "secret" 对 JWT 进行签名。

            boost::json::object data;
            data["token"] = token;
            boost::json::object root;
            root["code"] = 1;
            root["msg"] = nullptr;
            root["data"] = data;

            beast::ostream(connection->_response.body()) << serialize(root);
        }
        else {
            boost::json::object root;
            root["code"] = 0;
            root["msg"] = "password error";
            root["data"] = nullptr;
            beast::ostream(connection->_response.body()) << serialize(root);
        }
    });

    RegisterPost("/get_verify_code", [](const std::shared_ptr<HttpConnection>& connection) {
        const auto body_str = buffers_to_string(connection->_request.body().data());
        std::cout << "receive body is " << body_str << std::endl;
        connection->_response.set(http::field::content_type, "text/json");

        boost::json::object root;
        boost::system::error_code ec;
        boost::json::value decode_json = boost::json::parse(body_str, ec);
        if (ec) {
            std::cerr << "json解析失败，Json: " << body_str << " 错误原因: " << ec.message() << std::endl;
            root["error"] = Error_Json;
            beast::ostream(connection->_response.body()) << serialize(root);
            return;
        }
        if (decode_json.is_object()) {
            const auto email = decode_json.at("email").as_string();
            std::clog << "email is " << email << std::endl;
            //使用grpc拉起远程调用获取验证码

            beast::ostream(connection->_response.body()) << serialize(root);
        }
    });

    RegisterPost("/user_register", [](const std::shared_ptr<HttpConnection>& connection) {
        const auto body_str = buffers_to_string(connection->_request.body().data());
        std::cout << "receive body is " << body_str << std::endl;
        connection->_response.set(http::field::content_type, "text/json");
        //返回用json
        boost::json::object root;
        //解析json
        boost::system::error_code ec;
        boost::json::value json = boost::json::parse(body_str, ec);
        if (ec) {
            std::cerr << "json解析失败，Json: " << body_str << " 错误原因: " << ec.message() << std::endl;
            root["error"] = Error_Json;
            beast::ostream(connection->_response.body()) << serialize(root);
            return;
        }

        //先查找redis中email对应的验证码是否合理
        std::string verify_code;
        const std::string email = json.at("email").as_string().c_str();
        const bool b_get_verify = RedisMng::GetInstance()->GetByKey(email, verify_code);
        if (!b_get_verify) {
            std::cout << " get verify code expired" << std::endl;
            root["error"] = VerifyExpired;
            beast::ostream(connection->_response.body()) << serialize(root);
            return;
        }
        if (verify_code != json.at("verifyCode").as_string().c_str()) {
            std::cout << " verify code error" << std::endl;
            root["error"] = VerifyCodeErr;
            beast::ostream(connection->_response.body()) << serialize(root);
            return;
        }
        //访问redis查找
        const bool b_usr_exist = RedisMng::GetInstance()->ExistsKey(json.at("user").as_string().c_str());
        if (b_usr_exist) {
            std::cout << " user exist" << std::endl;
            root["error"] = UserExist;
            beast::ostream(connection->_response.body()) << serialize(root);
            return;
        }

        //查找数据库判断用户是否存在
        root["error"] = 0;
        root["email"] = json.at("email").as_string();
        root["user"] = json.at("user").as_string();
        root["password"] = json.at("password").as_string();
        root["confirm"] = json.at("confirm").as_string();
        root["verifyCode"] = json.at("verifyCode").as_string();
        beast::ostream(connection->_response.body()) << serialize(root);
    });
}

bool LogicSystem::CheckJWT(const std::shared_ptr<HttpConnection>& connection) {
    try {
        const auto it = connection->_request.find("Authorization");
        if (it != connection->_request.end()) {
            std::string jwt = it->value();
            const size_t pos = jwt.find("Bearer ", 0, 7);
            if (pos != std::string::npos) {
                jwt.erase(pos, 7);
            }
            const auto decoded = jwt::decode(jwt);
            //string pay_load = decoded.get_payload();
            const auto verifier = jwt::verify()
                                  .with_issuer("DataMonitor")
                                  .allow_algorithm(jwt::algorithm::hs256{"haitong"});
            verifier.verify(decoded);
            return true;
        }
    }
    catch (std::exception& e) {
        cerr << "jwt err : " << e.what() << endl;
        return false;
    }
    return false;
}

bool LogicSystem::HandleHttp(const http::verb method, const std::string& path,
                             const std::shared_ptr<HttpConnection>& connection) {
    if (method == http::verb::get) {
        //判断路径是否被函数处理
        if (!_get_handlers.contains(path)) {
            connection->_response.result(http::status::not_found);
            beast::ostream(connection->_response.body()) << ResultError(404, "请求路径错误");
            return false;
        }
        //校验jwt是否正确
        if (!CheckJWT(connection)) {
            connection->_response.result(http::status::unauthorized);
            beast::ostream(connection->_response.body()) << ResultError(401, "jwt 校验失败");
            return false;
        }
        //执行处理
        _get_handlers[path](connection);
        return true;
    }
    else if (method == http::verb::post) {
        //判断是否为免认证的接口
        if (path == "/login" || path == "/logout" || path == "/register") {
            _post_handlers[path](connection);
            return true;
        }
        //判断路径是否被函数处理
        if (!_post_handlers.contains(path)) {
            connection->_response.result(http::status::not_found);
            beast::ostream(connection->_response.body()) << ResultError(404, "请求路径错误");
            return false;
        }
        //校验jwt是否正确
        if (!CheckJWT(connection)) {
            connection->_response.result(http::status::unauthorized);
            beast::ostream(connection->_response.body()) << ResultError(401, "jwt 校验失败");
            return false;
        }
        //执行处理
        _post_handlers[path](connection);
        return true;
    }
    else {
        connection->_response.result(http::status::not_implemented);
        beast::ostream(connection->_response.body()) << ResultError(501, "暂时不支持的请求方式");
        return false;
    }
}

void LogicSystem::RegisterGet(const std::string& url, const HttpHandler& handler) {
    _get_handlers.insert(make_pair(url, handler));
}

void LogicSystem::RegisterPost(const std::string& url, const HttpHandler& handler) {
    _post_handlers.insert(make_pair(url, handler));
}

std::string LogicSystem::ResultError(const int code, const std::string& msg) {
    boost::json::object root;
    root["code"] = code;
    root["msg"] = msg;
    root["data"] = nullptr;
    return serialize(root);
}
